#pragma once
#include "base.h"
#include "object_manager.h"
#include <device_launch_parameters.h>

namespace shermit {
namespace lbvh {
namespace GPU {

	template<typename QueryManager_t, typename BVSOA_t>
	__global__ void traverseLbvhIntra(QueryManager_t object_manager, int leafSize, LBvhLeaves<BVSOA_t> leaves, LBvhInteriors<BVSOA_t> interiors) {
		int idx = blockIdx.x * blockDim.x + threadIdx.x;
		if (idx >= leafSize - 1) return;
		//if (idx > 0) return;

		const auto bv_i = leaves.bv.getBV(idx);
		int ia = leaves.primIdx[idx];

		// do sprouting
		int L = 0, R = 0;
		bool overlap = false;
		int interior_idx = 0;
		for (int leaf_idx = idx + 1; leaf_idx < leafSize; leaf_idx++) {
			L = leaves.segOffset[leaf_idx];
			R = leaf_idx == leafSize - 1 ? L : leaves.segOffset[leaf_idx + 1];
			overlap = true;
			for (interior_idx = L; interior_idx < R; ++interior_idx) {
				overlap = interiors.bv.overlap(interior_idx, bv_i);
				if (!overlap) {
					leaf_idx = interiors.rangeR[interior_idx];
					break;
				};
			}
			if (!overlap) continue;

			if (leaves.bv.overlap(leaf_idx, bv_i)) {
				int ib = leaves.primIdx[leaf_idx];
				object_manager.storeIntersection(ia, ib);
			}
		}
	}

	template<typename QueryManager_t, typename BVSOA_t>
	__global__ void traverseLbvhCustom(QueryManager_t object_manager, int leafSize, LBvhLeaves<BVSOA_t> leaves, LBvhInteriors<BVSOA_t> interiors) {
		int idx = blockIdx.x * blockDim.x + threadIdx.x;
		if (idx >= object_manager.primSize()) return;
		//if (idx > 0) return;

		const auto obj_i = object_manager.get(idx);

		// do sprouting
		int L = 0, R = 0;
		bool overlap = false;
		int interior_idx = 0;
		for (int leaf_idx = 0; leaf_idx < leafSize; leaf_idx++) {
			L = leaves.segOffset[leaf_idx];
			R = leaf_idx == leafSize - 1 ? L : leaves.segOffset[leaf_idx + 1];
			overlap = true;
			for (interior_idx = L; interior_idx < R; ++interior_idx) {
				overlap = QueryManager_t::intersect(obj_i, interiors.bv, interior_idx);
				if (!overlap) {
					leaf_idx = interiors.rangeR[interior_idx];
					break;
				};
			}
			if (!overlap) continue;

			if (QueryManager_t::intersect(obj_i, leaves.bv, leaf_idx)) {
				int ib = leaves.primIdx[leaf_idx];
				object_manager.storeIntersection(idx, ib);
			}
		}
	}

}
}
}